/***************************************************************************
 *   Copyleft 2008-2009 by												   *
 *	 Iwanicki Krzysztof													   *
 *   <gamma.mini.pw.edu.pl/~iwanickik>									   *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 *   This program is distributed in the hope that it will be useful,       *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU General Public License for more details.                          *
 ***************************************************************************/
#ifdef V_WIN32_PLATFORM

#include "../vEngine3D.h"
#include "../../Window/Win32/vWin32MainWindow.h"
#include "./vWin32GLAPI.h"
#include "./vWin32GlExtensionManager.h"
#include "../../Macros/vMacros.h"

namespace Vendetta {
	vWin32GlApi::vWin32GlApi() {
		// FIXME: from environment
		mBPP = 32;
		mZBufferBPP = 16;
		mStencilBPP = 8;
	}

	vWin32GlApi::~vWin32GlApi()	{
	}

	// Initializes API
	vBool vWin32GlApi::init() {
		static PIXELFORMATDESCRIPTOR pixelFormatDescriptor = {
			sizeof(PIXELFORMATDESCRIPTOR),
			1,
			PFD_DRAW_TO_WINDOW |
			PFD_SUPPORT_OPENGL |
			PFD_DOUBLEBUFFER,
			PFD_TYPE_RGBA,
			mBPP,
			0, 0, 0, 0, 0, 0,
			0,
			0,
			0,
			0, 0, 0, 0,
			mZBufferBPP,
			mStencilBPP,
			0,
			PFD_MAIN_PLANE,
			0,
			0, 0, 0
		};

		if (!(mDC = ::GetDC(((vWin32MainWindow*) vEngine3D::InstancePtr()->MainWindowPtr())->WindowHandle()))) {
			LOGS_ERROR("Couldn't create OpenGL device context.");
			kill();
			return false;
		}

		vInt PixelFormat;
		if (!(PixelFormat = ::ChoosePixelFormat(mDC, &pixelFormatDescriptor))) {
			LOGS_ERROR("Couldn't find suitable pixel format.");
			kill();
			return false;
		}

		if (!::SetPixelFormat(mDC, PixelFormat, &pixelFormatDescriptor)) {
			LOGS_ERROR("Couldn't set pixel format.");
			kill();
			return false;
		}

		if (!(mGLRC = ::wglCreateContext(mDC))) {
			LOGS_ERROR("Couldn't create OpenGL rendering context.");
			kill();
			return false;
		}

		if (!::wglMakeCurrent(mDC, mGLRC)) {
			LOGS_ERROR("Couldn't activate OpenGL rendering context.");
			kill();
			return false;
		}

		LOGS_INFO("OpenGL context set successfully:");
		LOGS_INFO("  Renderer: %s", (vChar*) glGetString(GL_RENDERER));
		LOGS_INFO("  Vendor: %s", (vChar*) glGetString(GL_VENDOR));
		LOGS_INFO("  Version: %s", (vChar*) glGetString(GL_VERSION));

		//if (!(GLExtensionManager = monsterNew cWin32GLExtensionManager) ||
		if (!(vGlApi::init())) {
			LOGS_ERROR("Couldn't Initialize OpenGL API.");
			kill();
			return false;
		}
		mpGlExtensionManager = new vWin32GlExtensionManager;

		if (!mpGlExtensionManager->Init()) {
			return false;
		}

		return true;
	}

	// Kills API
	vVoid vWin32GlApi::kill() {
		vGlApi::kill();

		if (mGLRC) {
			if (!::wglMakeCurrent(vNull, vNull)) {
				LOGS_ERROR("Couldn't release OpenGL device context and rendering context.");
			}
			if (!::wglDeleteContext(mGLRC)) {
				LOGS_ERROR("Couldn't release OpenGL rendering context.");;
				mGLRC = vNull;
			}
		}

		if (mDC) {
			if (!::ReleaseDC(((vWin32MainWindow*) vEngine3D::InstancePtr()->MainWindowPtr())->WindowHandle(), mDC)) {
				LOGS_ERROR("Couldn't release device context.");
				mDC = vNull;
			} else {
				LOGS_INFO("OpenGL context released");;
			}
		}
	}

	// Per frame API Update
	vVoid vWin32GlApi::Update() {
		vGlApi::Update();
	}

	// Swaps color buffers
	vVoid vWin32GlApi::SwapColorBuffers() {
		SwapBuffers(mDC);
	}

	//// Returns API specific (only!) object
	//vVoid* vWin32GlApi::newObject(const vInt objectmName) {
	//	switch (objectmName) {
	//		case API_OBJECT_RENDER_TARGET : return monsterNew cWin32GLRenderTarget;
	//		}
	//	// If it's not a Win32 specifc OpenGL object, then try with
	//	// platform independent objects
	//	return vGlApi::newObject(objectmName);
	//}

	HDC vWin32GlApi::GetDC() const {
		return mDC;
	}

	HGLRC vWin32GlApi::GetGLRC() const {
		return mGLRC;
	}
}

#endif // V_WIN32_PLATFORM